package pt.um.jspecput.lib.writer;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import java.util.ArrayList;

import javax.validation.constraints.Pattern;

import org.databene.benerator.anno.InvocationCount;
import org.databene.feed4junit.Feeder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import antlr.collections.List;

import com.google.common.collect.Lists;

@RunWith(Feeder.class)
public class ClassTest {

    private static Class testClass;

    @Before
    public void setUp() throws Exception {
        testClass = new Class();
    }

    @After
    public void tearDown() throws Exception {
        testClass = null;
    }

    @Test
    public void testClass() {
        Class c1 = new Class();

        assertNotNull(c1);
    }

    @Test
    public void testClass_Args() {
        String className = "ClassOne";

        Class c1 = new Class(className);

        assertNotNull(c1);
    }

    @Test
    @InvocationCount(10)
    public void testSetGetPackageName(String packageName) {
        testClass.setPackageName(packageName);

        assertEquals(packageName, testClass.getPackageName());
    }

    @Test
    public void testSetGetImportDeclarations() {
        ArrayList<String> importDeclarations = Lists.newArrayList();

        testClass.setImportDeclarations(importDeclarations);

        assertEquals(importDeclarations, testClass.getImportDeclarations());
    }

    @Test
    @InvocationCount(10)
    public void testSetGetClassName(
            @Pattern(regexp = "[A-Z][a-zA-Z0-9]*") String className) {
        testClass.setClassName(className);

        assertEquals(className, testClass.getClassName());
    }

    @Test
    public void testHashCode_nullFields() {
        Class c1 = new Class();

        int result = c1.hashCode();

        assertEquals(103823, result);
    }

    @Test
    public void testHashCode_validFields() {
        Class c1 = new Class();
        c1.setClassName("ClassOne");

        ArrayList<String> importDeclarations = new ArrayList<String>();
        importDeclarations.add("java.lang.Math");
        c1.setImportDeclarations(importDeclarations);

        c1.setPackageName("package");

        int result = c1.hashCode();

        assertEquals(-1927421672, result);
    }

    @Test
    public void testEquals_sameObject() {
        assertTrue(testClass.equals(testClass));
    }

    @Test
    public void testEquals_nullObject() {
        assertFalse(testClass.equals(null));
    }

    @Test
    public void testEquals_otherObject() {
        assertFalse(testClass.equals(mock(List.class)));
    }

    @Test
    @InvocationCount(10)
    public void testEquals_ClassName(
            @Pattern(regexp = "[A-Z][a-zA-Z0-9]*") String className) {
        Class c1 = new Class();
        Class c2 = new Class();

        c1.setClassName(null);
        c2.setClassName(null);

        assertTrue(c1.equals(c2));
        assertTrue(c2.equals(c1));

        c1.setClassName(null);
        c2.setClassName(className);

        assertFalse(c1.equals(c2));
        assertFalse(c2.equals(c1));

        c1.setClassName(className);
        c2.setClassName(null);

        assertFalse(c1.equals(c2));
        assertFalse(c2.equals(c1));

        c1.setClassName(className);
        c2.setClassName(className);

        assertTrue(c1.equals(c2));
        assertTrue(c2.equals(c1));
    }

    @Test
    @InvocationCount(10)
    public void testEquals_PackageName(
            @Pattern(regexp = "[a-z][a-zA-Z0-9]*") String packageName) {
        Class c1 = new Class();
        Class c2 = new Class();

        c1.setPackageName(null);
        c2.setPackageName(null);

        assertTrue(c1.equals(c2));
        assertTrue(c2.equals(c1));

        c1.setPackageName(null);
        c2.setPackageName(packageName);

        assertFalse(c1.equals(c2));
        assertFalse(c2.equals(c1));

        c1.setPackageName(packageName);
        c2.setPackageName(null);

        assertFalse(c1.equals(c2));
        assertFalse(c2.equals(c1));

        c1.setPackageName(packageName);
        c2.setPackageName(packageName);

        assertTrue(c1.equals(c2));
        assertTrue(c2.equals(c1));
    }

    @Test
    public void testEquals_ImportDeclarations() {
        Class c1 = new Class();
        Class c2 = new Class();
        ArrayList<String> importDeclarations = Lists.newArrayList();

        c1.setImportDeclarations(null);
        c2.setImportDeclarations(null);

        assertTrue(c1.equals(c2));
        assertTrue(c2.equals(c1));

        c1.setImportDeclarations(null);
        c2.setImportDeclarations(importDeclarations);

        assertFalse(c1.equals(c2));
        assertFalse(c2.equals(c1));

        c1.setImportDeclarations(importDeclarations);
        c2.setImportDeclarations(null);

        assertFalse(c1.equals(c2));
        assertFalse(c2.equals(c1));

        c1.setImportDeclarations(importDeclarations);
        c2.setImportDeclarations(importDeclarations);

        assertTrue(c1.equals(c2));
        assertTrue(c2.equals(c1));
    }

    @Test
    @InvocationCount(10)
    public void testToString(
            @Pattern(regexp = "[A-Z][a-zA-Z0-9]") String className,
            @Pattern(regexp = "[a-z][a-zA-Z0-9]") String packageName) {
        testClass.setClassName(className);
        testClass.setPackageName(packageName);
        
        String expected = "Class: " + packageName + "." + className;
        assertEquals(expected, testClass.toString());
    }
}
